package com.rw.tool.util.io;

import com.rw.tool.util.io.exception.StreamIOException;
import com.rw.tool.util.json.CastUtil;

import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

/**
 * 流操作工具类
 */
public class StreamUtil {
    // 默认缓存大小
    private static final int DEFAULT_BUFFER = 4096;

    /**
     * 复制流
     * 注意：该方法不负责关闭传递的输入流和输出流
     *
     * @param inputStream  输入流
     * @param outputStream 输出流
     * @param bufferSize   缓存大小
     */
    public static void copyStream(InputStream inputStream, OutputStream outputStream, int bufferSize) {
        try {
            byte[] buffer = new byte[bufferSize];
            int len;
            while ((len = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, len);
            }
        } catch (IOException e) {
            throw new StreamIOException(e);
        }
    }

    /**
     * 复制流
     * 注意：该方法不负责关闭传递的输入流和输出流
     *
     * @param inputStream  输入流
     * @param outputStream 输出流
     */
    public static void copyStream(InputStream inputStream, OutputStream outputStream) {
        copyStream(inputStream, outputStream, DEFAULT_BUFFER);
    }

    /**
     * 读取输入流中所有的字符
     * 注意：该方法不负责关闭传递的输入流。
     */
    public static String readAll(InputStream inputStream) {
        return readAll(inputStream, StandardCharsets.UTF_8);
    }

    /**
     * 读取文件中所有的字符
     * 注意：该方法不负责关闭传递的输入流。
     */
    public static String readAll(InputStream inputStream, Charset charset) {
        return new String(readAllBytes(inputStream), charset);
    }

    /**
     * 读取文件中所有的字节
     * 注意：该方法不负责关闭传递的输入流。
     */
    public static byte[] readAllBytes(InputStream inputStream) {
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            StreamUtil.copyStream(inputStream, outputStream);
            return outputStream.toByteArray();
        } catch (IOException e) {
            throw new StreamIOException(e);
        }
    }

    /**
     * 向文件中写入全部字节
     * 注意：该方法不负责关闭传递的输出流。
     */
    public static void writeAllBytes(OutputStream outputStream, byte[] bytes) {
        try {
            outputStream.write(bytes);
        } catch (IOException e) {
            throw new StreamIOException(e);
        }
    }

    /**
     * 读取文件保存的对象
     * 注意：该方法不负责关闭传递的输入流。
     */
    public static <T> T readObject(InputStream inputStream) {
        try (ObjectInputStream ois = new ObjectInputStream(inputStream)) {
            return CastUtil.castObj(ois.readObject());
        } catch (IOException | ClassNotFoundException e) {
            throw new StreamIOException(e);
        }
    }

    /**
     * 读取文件保存的对象
     * 注意：该方法不负责关闭传递的输入流。
     */
    public static void writeObject(OutputStream outputStream, Serializable obj) {
        try (ObjectOutputStream oos = new ObjectOutputStream(outputStream)) {
            oos.writeObject(obj);
        } catch (IOException e) {
            throw new StreamIOException(e);
        }
    }

    /**
     * 关闭所有可关闭的流
     */
    public static void closeAll(AutoCloseable... closeables) {
        for (AutoCloseable closeable : closeables) {
            try {
                closeable.close();
            } catch (Exception e) {
                throw new StreamIOException(e);
            }
        }
    }
}
